const mongoose = require("mongoose")
const bcrypt = require("bcrypt")
const SALT_WORK_FACTOR = 10
const MAX_LOGIN_ATTEMPTS = 5
const LOCK_TIME = 2 * 60 * 60 * 1000
const Schema = mongoose.Schema
const Mixed = Schema.Types.Mixed

//设置数据库表,unique唯一,required必填
const UserShema = new Schema({

    username: {
        unique: true,
        type: String,
        required:true
    },

    email: {
        unique: true,
        type: String,
        require:true
    },

    password: {
        type: String,
        required:true
    },

//密码尝试次数
    loginAttepts:{
        type:Number,
        default:0,
        required:true
    },
    //用户锁定时间
    lockUntil: Number,

    meta: {
        createdAt: {
            type: Date,
            default: Date.now(),
        },
        upDatedAt: {
            type: Date,
            default: Date.now(),
        }
    }
})

//虚拟字段
UserShema.virtual('isLocked').get(function() {
    return this.lockUntil && this.lockUntil > Date.now()
})

//在save之前更新时间
UserShema.pre('save',function(next)   {
    if (this.isNew) {
        this.meta.createdAt = this.meta.upDatedAt = Date.now()
    } else {
        this.meta.upDatedAt = Data.now()
    }
    next()
})

//在save之前给密码加盐,把加盐之后的密码存到数据库
UserShema.pre("save", function(next)  {
    if (!this.isModified('passwoed')) return next()
    bcrypt.genSalt(SALT_WORK_FACTOR, (err, salt) => {
        if (err) {
            return next(err)
        } else {
            bcrypt.hash(this.password, salt, (err, hash) => {
                if (err) {
                    return next(err)
                } else {
                    this.password = hash
                    next()
                }
            })
        }
    })
})

//定义实例方法,还有一个概念叫做静态方法,这里先不深究,以后用到查资料
UserShema.methods = {
    //判断密码正确与否,返回promise对象
    comparePassword: (_password, password) => {
        return new Promise((resolve, reject) => {
            bcrypt.compare(_password, password, (err, isMatch) => {
                if (!err) {
                    resolve(isMatch)
                } else {
                    reject(err)
                }
            })
        })
    },

    //判断登录次数,大于最大次数则锁住一段时间,返回promise对象
    incLoginAttepts: (user) => {
        return new Promise((resolve, reject) => {
            if (this.lockUntil && this.lockUntil < Date.now()) {
                this.update({
                    //$set,原子操作,设置为..
                    $set: {
                        loginAttepts: 1
                    },
                    //unset原子操作,置为null
                    $unset: {
                        lockUntil: 1,
                    }
                }, (err) => {
                    if (!err) resolve(true)
                    else reject(err)
                })
            } else {
                let updates = {
                    $inc: {
                        loginAttepts: 1
                    }
                }
                if (loginAttepts + 1 > MAX_LOGIN_ATTEMPTS && !this.isLocked) {
                    updates.$set = {
                        lockUntil: Date.now() + LOCK_TIME
                    }
                }
                //将上面两个原子操作注册
                this.update(updates,(err)=>{
                    if(!err) resolve(true)
                    else reject(err)
                })
            }
        })

    }
}

// UserShema.pre("")

mongoose.model('User', UserShema)